const particle =/*wgsl*/`
const PI =3.1415926535897932384626433832795;
const DEG2RAD =PI / 180;
struct Particle {
    position : vec3<f32>,
    size : f32,
    color    : vec3<f32>,
    opacity:f32,
    velocity : vec3<f32>,
    age : f32,
    angle: f32,
    alive:f32,
  }
  struct Particles {
    particles : array<Particle>,
  }
  struct Colors {
    color : array<vec3<f32>>,
  }
  struct Sizes {
    size : array<f32>,
  }
  struct Opacitys {
    opacity : array<f32>,
  }
  struct Times {
    time : array<f32>,
  }
  struct EmitterParams {
    position : vec3<f32>,
    positionShape : f32,
    positionRange : vec3<f32>,
    positionRadius:f32,

    velocity:vec3<f32>,
    velocityShape:f32,
    velocityRange:vec3<f32>,
    velocityRadius:f32,


    acceleration:vec3<f32>,
    angle:f32,
    angleRange:f32,
    angleVelocity:f32,
    positionconeHeight:f32,
    duration : f32,
    velocityconeHeight:f32,
  }
  struct FrameParams {
    deltaTime : f32,
    frameID : f32,
    startIndex:f32,
    endIndex:f32,
    seed : vec4f,
  }
  @group(0) @binding(0)  var<uniform> params : EmitterParams;
  @group(0) @binding(1)  var<uniform> frameParams : FrameParams;
  @group(0) @binding(2)  var<storage, read> sizes : Sizes;
  @group(0) @binding(3)  var<storage, read> sizeTimes:Times;
  @group(0) @binding(4)  var<storage, read> colors : Colors;
  @group(0) @binding(5)  var<storage, read> colorTimes :Times;
  @group(0) @binding(6)  var<storage, read> opacitys : Opacitys;
  @group(0) @binding(7)  var<storage, read> opacityTimes : Times;
  @group(0) @binding(8)  var<storage, read_write> data : Particles;

fn randomVector3(min: vec3<f32>, max: vec3<f32>) -> vec3<f32> {
  var rand3: vec3<f32> = vec3<f32>(rand(), rand(), rand()) - vec3<f32>(0.5, 0.5, 0.5);
  var scaledMax: vec3<f32> = max * rand3;
  return min + scaledMax;
}
fn randomValue(min: f32, max: f32) -> f32 {
  return min + max * (rand() - 0.5);
}

fn random(seed: u32) -> f32 {  
  const a: u32 = 1664525;  
  const c: u32 = 1013904223;  
  const m: u32 = 0xFFFFFFFF;  

  var newSeed: u32 = (a * seed + c) % m;  
  return f32(newSeed/ m) ;  
}  

fn randomInRange(min: vec3<f32>, max: vec3<f32>, seed: u32) -> vec3<f32> {  
  // 使用简单的伪随机数生成算法  
  // 只需确保这一部分可以产生重复的结果  
  let randomValue = f32(seed) * 0.5 + 0.1; // 确保是正数  

  let randomX = min.x + fract(sin(randomValue) * 43758.5453) * (max.x - min.x);  
  let randomY = min.y + fract(sin(randomValue * 1.5) * 43758.5453) * (max.y - min.y);  
  let randomZ = min.z + fract(sin(randomValue * 3.0) * 43758.5453) * (max.z - min.z);  
  
  return vec3<f32>(randomX, randomY, randomZ);  
}  
var<private> rand_seed1 : vec2f;

fn init_rand(invocation_id : u32, seed : vec4f) {
  rand_seed1 = seed.xz;
  rand_seed1 = fract(rand_seed1 * cos(35.456+f32(invocation_id) * seed.yw));
  rand_seed1 = fract(rand_seed1 * cos(41.235+f32(invocation_id) * seed.xw));
}
fn lerp(a: f32, b: f32, t: f32) -> f32 {  
  return a + t * (b - a);  
}  

fn rand() -> f32 {
  rand_seed1.x = fract(cos(dot(rand_seed1, vec2f(23.14077926, 232.61690225))) * 136.8168);
  rand_seed1.y = fract(cos(dot(rand_seed1, vec2f(54.47856553, 345.84153136))) * 534.7645);
  return rand_seed1.y;
}
var<private> p : Particle;
@compute @workgroup_size(64)
fn main(   
@builtin(workgroup_id) workgroup_id : vec3<u32>,
@builtin(local_invocation_id) local_invocation_id : vec3<u32>,
@builtin(global_invocation_id) global_invocation_id : vec3<u32>,
@builtin(local_invocation_index) local_invocation_index: u32,
@builtin(num_workgroups) num_workgroups: vec3<u32>)
{
  let idx = global_invocation_id.x;
  init_rand(idx, frameParams.seed);
  if (idx >= arrayLength(&data.particles)) {
    return;
  }
  // if(0<1){return;}
  // init_rand(idx, frameParams.seed);
  var particle = data.particles[idx];
  if(particle.alive==1.0){
    // if(0<1){return;}
    if(particle.age >= params.duration) {
      // particle.alive = 0;
      if(params.positionShape ==1.0){//box
        particle.position = randomVector3(params.position,params.positionRange);
      }
      if(params.positionShape ==2.0){//Sphere
        let z = 2.0 * rand() - 1.0;
        let theta = 2.0 * PI * rand();
        let r = sqrt(1.0 - z * z);
        let vec3 = vec3<f32>(r * cos(theta), r * sin(theta), z);
        particle.position = params.position + vec3 * params.positionRadius;
      }
      if(params.positionShape ==3.0){//Circle
        var angle = rand() * 2 * PI;
        var radius = rand() * params.positionRadius;
        particle.position = vec3<f32>(
          params.position.x + radius *cos(angle),
          params.position.y + radius *sin(angle),
          params.position.z // 圆形平面的z坐标保持不变
        );
      }
      if(params.positionShape ==4.0){//Cone
        var height: f32 = rand() * params.positionconeHeight;
        var radius: f32 = (rand() * params.positionRadius) * (1.0 - height / params.positionconeHeight);
        var angle: f32 = rand() * 2.0 * PI;
    
        var x: f32 = radius * cos(angle);
        var y: f32 = height;
        var z: f32 = radius * sin(angle);
    
        // 在WGSL中，vec3.add() 方法可能并不存在，我们直接使用加法运算符 '+'。
        var particle_pos: vec3<f32> = vec3<f32>(x, y, z) + params.position;
        particle.position = particle_pos;
      }
      if(params.positionShape ==5.0){//Hemisphere
        var z:f32 = sqrt(1 - pow((rand() * 2.0 - 1.0),2)); // 限制在半球范围内
        var t = PI * 2 * rand();
        var r = sqrt(1 - z * z);
        var vec3R =vec3<f32>(r * cos(t), r * sin(t), z)*params.positionRadius;
        particle.position = params.position+vec3R;
      }
      if(params.velocityShape ==1.0){//box
        particle.velocity = randomVector3(params.velocity,params.velocityRange);
      }
      if(params.velocityShape ==2.0){//Sphere
        var direction = particle.position-params.position;
        var speed = randomValue(params.velocity.x, params.velocityRadius);
        particle.velocity = normalize(direction)*speed;
      }
      if(params.velocityShape ==3.0){//Circle
        var angle = rand() * 2 * PI;
        var speed = randomValue(params.velocity.x, params.velocityRadius);
        particle.velocity = vec3<f32>(
            speed * cos(angle),
            speed * sin(angle),
            0 // 圆形平面的z分量速度设为0
        );
      }
      if(params.velocityShape ==4.0){//Cone
        var heightRatio = rand();
        var baseRadius = params.velocityRadius * sqrt(heightRatio);
        var angle = rand() * 2 * PI;
        var speed = randomValue(params.velocity.x, params.velocityRadius);
    
        var x = speed * baseRadius * cos(angle);
        var y = speed * heightRatio * params.velocityconeHeight;
        var z = speed * baseRadius * sin(angle);
    
        particle.velocity = vec3<f32>(x, y, z);
      }
      if(params.velocityShape ==5.0){//Hemisphere
        var phi = acos(1 - 2 * rand()); // 高度角，限制在半球内
        var theta =rand() * 2 * PI; // 方位角
        var speed = randomValue(params.velocity.x, params.velocityRadius);
    
        var x = speed * sin(phi) * cos(theta);
        var y = speed * sin(phi) * sin(theta);
        var z = speed * cos(phi);
        particle.velocity = vec3<f32>(x, y, z);
      }
      particle.angle = randomValue(params.angle, params.angleRange);
      particle.size = sizes.size[0];
      particle.color = colors.color[0];
      particle.opacity = opacitys.opacity[0];
      particle.age= rand()/2 ;
      // particle.alive=1.0;
    }else{
      particle.position+=(particle.velocity*frameParams.deltaTime);
      particle.velocity+=(params.acceleration*frameParams.deltaTime);
      particle.angle+=(params.angleVelocity*DEG2RAD*frameParams.deltaTime);
      // particle.angle+=params.angleVelocity;
      particle.age+=frameParams.deltaTime;
      // 大小
      if (particle.age <= sizeTimes.time[0]) {  
        particle.size= sizes.size[0];  
      } else if (particle.age >= sizeTimes.time[arrayLength(&sizeTimes.time) - 1]) {  
        particle.size= sizes.size[arrayLength(&sizeTimes.time) - 1];  
      }  
      var indexSize: i32 = -1;  
      for (var iSize: i32 = 0; iSize < i32(arrayLength(&sizeTimes.time) - 1) ; iSize = iSize + 1) {  
        if (particle.age  >= sizeTimes.time[iSize] && particle.age  <= sizeTimes.time[iSize + 1]) {  
          indexSize = iSize;  
            break;  
        }  
       }  
      if (indexSize == -1) {  
         particle.size= sizes.size[0];  
       }  
      var sizeRate: f32 = (particle.age - sizeTimes.time[indexSize]) / (sizeTimes.time[indexSize + 1] - sizeTimes.time[indexSize]);  
      particle.size= lerp(sizes.size[indexSize], sizes.size[indexSize + 1], sizeRate);  
     // 透明度
       if (particle.age <= opacityTimes.time[0]) {  
        particle.opacity= opacitys.opacity[0];  
      } else if (particle.age >= opacityTimes.time[arrayLength(&opacityTimes.time) - 1]) {  
        particle.opacity= opacitys.opacity[arrayLength(&opacityTimes.time) - 1];  
      }  
      var indexOpacity: i32 = -1;  
      for (var iOpacity: i32 = 0; iOpacity < i32(arrayLength(&opacityTimes.time) - 1) ; iOpacity = iOpacity + 1) {  
        if (particle.age  >= opacityTimes.time[iOpacity] && particle.age  <= opacityTimes.time[iOpacity + 1]) {  
          indexOpacity = iOpacity;  
            break;  
        }  
       }  
      if (indexOpacity == -1) {  
         particle.opacity= opacitys.opacity[0];  
       }  
      var opacityRate: f32 = (particle.age - opacityTimes.time[indexOpacity]) / (opacityTimes.time[indexOpacity + 1] - opacityTimes.time[indexOpacity]);  
      particle.opacity= lerp(opacitys.opacity[indexOpacity], opacitys.opacity[indexOpacity + 1], opacityRate);        
      // 颜色
      var indexColor: u32 = 0;  
      // 遍历 times 数组找到 t 的插入位置  
      for (var iColor: u32 = 0; iColor < arrayLength(&colorTimes.time) - 1; iColor = iColor + 1) {  
          if (particle.age >= colorTimes.time[iColor] && particle.age <= colorTimes.time[iColor + 1]) {  
            indexColor = iColor;  
              break;  
          }  
      }  
      // 计算插值的比例  
      var t0Color: f32 = colorTimes.time[indexColor];  
      var t1Color: f32 = colorTimes.time[indexColor + 1];  
      var value0Color:vec3<f32> = colors.color[indexColor];  
      var value1Color:vec3<f32> = colors.color[indexColor + 1];  
      // 计算插值比例  
      var alphaColor: f32 = (particle.age - t0Color) / (t1Color - t0Color);  
      // 返回插值结果  
        particle.color= mix(value0Color, value1Color, alphaColor);  
    }
  }

  if(u32(frameParams.startIndex)<=idx &&idx<=u32(frameParams.endIndex)){
    particle.alive=1.0;
   }
  
 
   data.particles[idx] = particle;
}
`
export { particle }